package systems.lsystem 
{
	import flash.display.Sprite;
	/**
	 * @author Nicolas Barradeau
	 * http://en.nicoptere.net
	 */
	public class Lsystem extends Sprite
	{
		private var _axiom:String;
		private var _rule:String;
		private var _length:Number;
		private var _theta:Number;
		private var _delta:Number;
		
		protected var production:String;
		protected var generations:int;
		
		public function Lsystem( axiom:String = 'f', rule:String = 'f+f', length:Number = 10, theta:Number = 0, delta:Number = 0  ) 
		{
			
			_axiom 	= axiom;
			_rule 	= rule;
			_length = length;
			_theta 	= theta;
			_delta 	= delta;
			
		}
		
		public function render():void
		{
			
			var char:String;
			var turtle:Turtle = new Turtle(	0,0, theta 	);
			var tmp:Turtle = new Turtle();
			
			graphics.clear();
			graphics.lineStyle( 0, 0 );
			graphics.moveTo( turtle.x, turtle.y );
			
			for ( var i:int = 1; i < production.length; i++) 
			{
				
				char = production.charAt(i).toLowerCase();
				
				if ( char == 'f' || char == '+' || char == '-' )
				{
					process( char, turtle );
				}
				
				if ( char == '[' )
				{
					
					if ( production.substr( i+1, production.length ).lastIndexOf( ']' ) == -1 ) continue;
					
					tmp = turtle.clone();
					
					while ( char != ']')
					{
						char = production.charAt( i++ );
						process( char, tmp );
					}
					
					graphics.drawCircle( turtle.x, turtle.y, 2 );
					graphics.moveTo( turtle.x, turtle.y );
					
				} 
				
			}
			
		}
		
		public function process(step:String, turtle:Turtle ):void 
		{
			
			if (step == 'f')
			{
				
				turtle.x += Math.cos( turtle.angle ) * length;
				turtle.y += Math.sin( turtle.angle ) * length;
				graphics.lineTo( turtle.x, turtle.y );
				
			} 
			else if (step == '+')
			{
				turtle.angle += delta;
			} 
			else if (step == '-') 
			{
				turtle.angle -= delta;
			} 
			
		}

		public function compute( gens:int ):void
		{
			
			generations = 0;
			production = axiom.toLowerCase();
			var prod:String;
			while ( generations < gens ) 
			{
				
				prod = '';
				
				for ( var i:int = 0; i < production.length; i++ )
				{
					if ( production.charAt( i ) == 'f' )
					{
						prod += rule;
					}
					else
					{
						prod += production.charAt( i );
					}
				}
				
				production = prod;
				generations++;
				
			}
			
		}

		
		public function get axiom():String { return _axiom; }
		
		public function set axiom(value:String):void 
		{
			_axiom = value.toLowerCase();
		}
		
		public function get rule():String { return _rule; }
		
		public function set rule(value:String):void 
		{
			_rule = value.toLowerCase();
		}
		
		public function get theta():Number { return _theta; }
		
		public function set theta(value:Number):void 
		{
			_theta = value;
		}
		
		public function get delta():Number { return _delta; }
		
		public function set delta(value:Number):void 
		{
			_delta = value;
		}
		
		public function get length():Number { return _length; }
		
		public function set length(value:Number):void 
		{
			_length = value;
		}
		
	}

}


